﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IpAddress.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Types
{
  using System;
  using System.ComponentModel;
  using System.Globalization;
  using System.Net;

  using Lextm.SharpSnmpLib;

  /// <summary>
  /// Converts batch and forth from SNMP (per 1135-SMI) IpAddress to <see cref="IPAddress"/>.
  /// </summary>
  /// <remarks>
  /// IpAddress ::=
  ///        [APPLICATION 0]          -- in network-byte order
  ///            IMPLICIT OCTET STRING (SIZE (4)) 
  /// </remarks>
  public sealed class IpAddress : TypeConverter
  {
    #region Public Methods and Operators

    /// <summary>
    /// The can convert from.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="sourceType">
    /// The source type.
    /// </param>
    /// <returns>
    /// The System.Boolean.
    /// </returns>
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
      if (sourceType == typeof(IPAddress))
      {
        return true;
      }

      return base.CanConvertFrom(context, sourceType);
    }

    /// <summary>
    /// The can convert to.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="destinationType">
    /// The destination type.
    /// </param>
    /// <returns>
    /// The System.Boolean.
    /// </returns>
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
      if (destinationType == typeof(IPAddress))
      {
        return true;
      }

      return base.CanConvertTo(context, destinationType);
    }

    /// <summary>
    /// Converts a <see cref="IPAddress"/> to a IpAddress encoded <see cref="OctetString"/>.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="culture">
    /// Using culture.
    /// </param>
    /// <param name="value">
    /// The <see cref="IPAddress"/> value.
    /// </param>
    /// <returns>
    /// A <see cref="OctetString"/> encoded as IpAddress as defined in 1135-SMI.
    /// </returns>
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
      if (!(value is IPAddress))
      {
        return base.ConvertFrom(context, culture, value);
      }

      string[] components = value.ToString().Split('.');

      var data = new byte[4];

      data[0] = (byte)int.Parse(components[0]);
      data[1] = (byte)int.Parse(components[1]);
      data[2] = (byte)int.Parse(components[2]);
      data[3] = (byte)int.Parse(components[3]);

      return new OctetString(data);
    }

    /// <summary>
    /// Converts a <see cref="OctetString"/> encoded as IpAddress to a <see cref="IPAddress"/>.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="culture">
    /// Using culture.
    /// </param>
    /// <param name="value">
    /// The <see cref="OctetString"/> to be converted.
    /// </param>
    /// <param name="destinationType">
    /// A <see cref="IPAddress"/>.
    /// </param>
    /// <returns>
    /// A <see cref="IPAddress"/>from the inparam <see cref="OctetString"/>.
    /// </returns>
    public override object ConvertTo(
      ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
      if (!(value is OctetString) || (destinationType != typeof(IPAddress)))
      {
        return base.ConvertTo(context, culture, value, destinationType);
      }

      byte[] data = ((OctetString)value).GetRaw();

      return string.Format("{0}.{1}.{2}.{3}", data[0], data[1], data[2], data[3]);
    }

    #endregion
  }
}